package dabs.engine.environment;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Random;

import dabs.engine.Updatable;
import dabs.engine.messaging.*;
import dabs.engine.plant.*;

/**
 * This class generates the random events that affect our nuclear power plant.
 * Currently level increases every sixty seconds. Events initially appear every 30 seconds.
 * Each new level, the generation speed increases by that number of seconds.
 * 
 * (i.e. when player gets to level 2, speed increases by 2 seconds)
 * 
 * Events stored in a buffer so the player can be warned in advance of events.
 */
public class Environment implements Updatable, Serializable
{
	private static final long serialVersionUID = -2270218398641915994L;

	int warningTime; //Time between event generation and event effect.
	LinkedList<ModifierDestinationPair> buffer; //Event sequence.
	ArrayList<ComponentPart> canBeDisabled; //Components that can be disabled (currently the only event)
	
	NotificationHandler postOffice;
	PowerPlant powerPlant;
	
	Random random = new Random();
	
	int generationSpeed; //How often events should be started.
	int timeSinceLast; //Time since last event.
	int time; //Total running time, used to determine level.
	int level; //The level of the game, used to modify the generationSpeed to make the game harder.
	
	void setGenerationSpeed(int spd) { this.generationSpeed = spd; }
	int getGenerationSpeed() { return generationSpeed; }
	
	
	
	/*
	 * Constructor for the environment.
	 * canBeDisabled iterates through all the components, searching for specific components.
	 * Initializes the buffer so there can be a delay.
	 */
	public Environment(NotificationHandler poffice, PowerPlant powerPlant, int generationSpeed, int warningTime) {
		setGenerationSpeed(generationSpeed);
		time = 1;
		level = 1;
		this.warningTime = warningTime;
		this.postOffice = poffice;
		this.powerPlant = powerPlant;
		buffer = new LinkedList<ModifierDestinationPair>();
		canBeDisabled = new ArrayList<ComponentPart>();
		for(ComponentPart comp : powerPlant.getComponents()){
			if (comp instanceof Condenser || comp instanceof Pump || comp instanceof Reactor || comp instanceof Valve){
				canBeDisabled.add(comp);
			}
		}
		for (int i = 0; i < warningTime; ++i) buffer.add(null);
	}
	
	// don't you love overloading
	public Environment(NotificationHandler poffice, PowerPlant powerPlant) {
		this(poffice, powerPlant, 30, 30);
	}

	
	
	/*
	 * Tick function. Called every second. Determines how the environment changes over time	 * 
	 */
	public void tick() {
		
		time++;
		timeSinceLast++;
		
		//Levels increase every 60 seconds. Max level is 6 (10 events a second).
		if (time % 60 == 0){
			if (level < 6){
				level++;
				generationSpeed = generationSpeed - level;
			}
		}
		
		// every 'generationSpeed' we create a new disable.
		if (timeSinceLast > generationSpeed) {
			timeSinceLast = 0;
			generateDisable(10);
		} else {
			buffer.add(null);
		}
		
		
		//Removing elements of the buffer, and passing them if they are modifiers.
		ModifierDestinationPair mdp = buffer.removeFirst();
		if (mdp != null) mdp.getDestination().handleModifier(mdp.getModifier());
	}
	
	/*
	 * this function generates a disable event. Intention is that other functions can be created for different
	 * events.
	 * Picks a random component that can be disabled, and adds a disable to the buffer. Warns the player as
	 * it is added to the buffer. We are going to have custom warnings for different components (story 
	 * related)
	 */
	public void generateDisable(int time){
		
		//Generates an array of components that can be disabled.
		ArrayList<ComponentPart> newCanBeDisabled = new ArrayList<ComponentPart>();
		for(ComponentPart part : canBeDisabled) {
			if (!part.isDead()) newCanBeDisabled.add(part);
		}
		canBeDisabled = newCanBeDisabled;
		
		if (canBeDisabled.isEmpty()) { return; }
		
		ComponentPart part = canBeDisabled.get(random.nextInt(canBeDisabled.size()));
		buffer.add(new ModifierDestinationPair(new TemporaryDisable(time), part));
		
		if (part instanceof Condenser){
			postOffice.handleNotification( new Notification("Security", 
					"The rabbits are approaching! " + part.getName() + " stalling in " + warningTime + " seconds!"));
		}
		
		if (part instanceof Pump){
			postOffice.handleNotification( new Notification("Security", 
					"The rabbits are approaching! " + part.getName() + " stalling in " + warningTime + " seconds!"));
		}
		
		if (part instanceof Valve){
			postOffice.handleNotification( new Notification("Security", 
					"The rabbits are approaching! " + part.getName() + " being blocked in " + warningTime + " seconds!"));
		}
		
		if (part instanceof Reactor){
			postOffice.handleNotification( new Notification("Security", 
					"The rabbits are approaching! " + part.getName() + " rods stalling in " + warningTime + " seconds!"));
		}
	}

	public int getTiked(){
		return time-1;  //because it's initialised as 1
	}
	
}
